package models;

import util.MathUtils;


public class PerformanceModel{
	
	private double lambda;
	private double mu;
	private double p;
	private int m=0;
	
	public PerformanceModel(double lambda, double mu) {
		super();
		this.lambda = lambda;
		this.mu = mu;
		this.p=lambda/mu;
	}

	/**
	 * CDF = p0 *(a + b*(c - 1 + d))
	 * a = (1-d) * sum from 0 to m-1 of p^n/n!
	 * b = (mp^m)/m!(1-m+p)
	 * c = (1 - e^-(m-p)*mhu*x)/(m-p) 
	 * d = e^(-mhu*x)
	 * @param x
	 * @return CDF
	 */
	double calculateCDF(double x){
		double a=0;
		double b=0;
		double c=0;
		double d=0;
		
		d = Math.exp(-mu*x);
		
		for (int n=0; n<m; n++){
			a+= Math.pow(p, n)/MathUtils.factorial(n);
		}
		
		a = (1-d)*a;
		b = (m*Math.pow(p, m)) / (MathUtils.factorial(m)*(1 - m + p)); 
		c = (1 - Math.exp(-(m-p)*mu*x)) / (m-p);
		System.out.println("p=" + p +" a=" + a + " b= " + b + " c= " + c + " d= " + d + " p0=" + calculateP0(m,p));
		System.out.println("CDF: " + calculateP0(m, p)*(a + b*(c-1+d)));	
		return calculateP0(m, p)*(a + b*(c-1+d));		
	}
	
	/**
	 * P(0) = (a + b)^-1
	 * a = sum from 0 to m-1 of p^n/n!
	 * b = (mp^m)/m!(m-p)
	 * p = lambda/mhu
	 * @return P(0)
	 */
	private double calculateP0(int m, double p) {
		
		double a=0;
		double b=0;
				
		for (int n=0; n<m; n++){
			a += Math.pow(p, n)/MathUtils.factorial(n);
		}
		
		b = (m*Math.pow(p, m)) / (MathUtils.factorial(m)*(m - p)); 
		System.out.println("p0 a = " + a + " p0 b = " + b);
		return 1/(a+b);
	}
	
		
	public static void main(String[] args) {
		
//		PerformanceModel pmda = new PerformanceModel(6, 3, 0.1, true);
//		PerformanceModel pmsa = new PerformanceModel(6, 3, 0.1, false);
//
//		//System.out.println("alg1 (DA): " + pmda.alg1(5, 0.8, 5, 0.95));
//		System.out.println("alg1 (SA): " + pmsa.alg1(0.00000001, 0.8, 25, 0.95));
	
	}

	public double getLambda() {
		return lambda;
	}

	public void setLambda(double lambda) {
		this.lambda = lambda;
	}

	public double getMu() {
		return mu;
	}

	public void setMu(double mu) {
		this.mu = mu;
	}

	public double getP() {
		return p;
	}

	public void setP(double p) {
		this.p = p;
	}

	public int getM() {
		return m;
	}

	public void setM(int m) {
		this.m = m;
	}
	
	
}
